package com.clinic.logic.prescription;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.clinic.accessor.db.DrugAccessor;
import com.clinic.accessor.db.DrugIssueAccessor;
import com.clinic.accessor.db.DrugStockAccessor;
import com.clinic.accessor.db.PatientAccessor;
import com.clinic.accessor.db.PrescriptionAccessor;
import com.clinic.accessor.db.SyptomAccessor;
import com.clinic.entity.db.Drug;
import com.clinic.entity.db.DrugIssue;
import com.clinic.entity.db.DrugStock;
import com.clinic.entity.db.Patient;
import com.clinic.entity.db.Prescription;
import com.clinic.entity.db.Syptom;
import com.clinic.entity.gui.GuiDrugIssue;
import com.clinic.entity.gui.GuiPagination;
import com.clinic.entity.gui.GuiPatient;
import com.clinic.entity.gui.GuiPrescription;
import com.clinic.entity.gui.GuiSyptom;
import com.clinic.entity.param.Index;
import com.clinic.util.CommonUtil;
import com.clinic.util.ConvertUtil;

@Component
public class PrescriptionLogic {
	
	@Autowired
	private PrescriptionAccessor prescriptionAccessor;
	@Autowired
	private PatientAccessor patientAccessor;
	@Autowired
	private DrugAccessor drugAccessor;
	@Autowired
	private DrugIssueAccessor drugIssueAccessor;
	@Autowired
	private DrugStockAccessor drugStockAccessor;
	@Autowired
	private SyptomAccessor syptomAccessor;
	
	@Transactional
	public GuiPrescription getPrescriptionById(long id) {
		Prescription prescription = prescriptionAccessor.getPrescriptionById(id);
		GuiPrescription result = ConvertUtil.getGuiPrescriptionByPrescription(prescription);
		
		Prescription oRootPrescription = prescription.getRootPrescription();
		if (oRootPrescription != null) {
			Prescription rootPrescription = prescriptionAccessor.getPrescriptionById(oRootPrescription.getPrescriptionId());
			result.setRootPrescription(ConvertUtil.getGuiPrescriptionByPrescription(rootPrescription));
			List<Prescription> prevPrescriptionList = new ArrayList<>();
			
			if (rootPrescription != null) {
				prevPrescriptionList = prescriptionAccessor.getPrescriptionsByRootPrescriptionId(rootPrescription.getPrescriptionId());
				if (prevPrescriptionList != null && prevPrescriptionList.size() == 1) {
					// this is second prescription and prev should be root prescription
					prevPrescriptionList = new ArrayList<>();
				}
				prevPrescriptionList.add(rootPrescription);
			}
			
			if (prevPrescriptionList.size() > 0) {
				Prescription prevPrescription = prevPrescriptionList.get(0);
				result.setPrevPrescription(ConvertUtil.getGuiPrescriptionByPrescription(prevPrescription));
			}
		}
		
		
		List<GuiSyptom> guiSyptomList = new ArrayList<>();
		for (Syptom syptom : prescription.getSyptoms()) {
			GuiSyptom guiSyptom = ConvertUtil.getGuiSyptomBySyptom(syptom);
			guiSyptomList.add(guiSyptom);
		}
		result.setSyptomList(guiSyptomList);
		
		List<GuiDrugIssue> guiDrugIssueList = new ArrayList<>();
		for (DrugIssue drugIssue : prescription.getIssues()) {
			GuiDrugIssue guiDrugIssue = ConvertUtil.getGuiDrugIssueByDrugIssue(drugIssue);
			guiDrugIssue.setDrug(ConvertUtil.getGuiDrugByDrug(drugIssue.getDrug()));
			guiDrugIssueList.add(guiDrugIssue);
			
		}
		result.setDrugIssueList(guiDrugIssueList);
		
		result.setPatient(ConvertUtil.getGuiPatientByPatient(prescription.getPatient()));
		return result;
	}
	
	@Transactional
	public List<GuiPrescription> getPrescriptionsByPatientId(long patientId) {
		List<GuiPrescription> result = new ArrayList<>();
		List<Prescription> prescriptionList = prescriptionAccessor.getPrescriptionsByPatientId(patientId);
		for (Prescription prescription : prescriptionList) {
			result.add(ConvertUtil.getGuiPrescriptionByPrescription(prescription));
		}
		return result;
	}

	@Transactional
	public List<GuiPrescription> getPrescriptions(Index index) {
		List<GuiPrescription> result = new ArrayList<>();
		List<Prescription> prescriptionList = prescriptionAccessor.getPrescriptions(index);
		for (Prescription prescription : prescriptionList) {
			result.add(ConvertUtil.getGuiPrescriptionByPrescription(prescription));
		}
		return result;
	}
	
	@Transactional
	public GuiPrescription getPastPrescriptionOfPatient(long patientId) {
		Prescription pastPrescription = prescriptionAccessor.getPastPrescriptionOfPatient(patientId);
		return ConvertUtil.getGuiPrescriptionByPrescription(pastPrescription);
	}
	
	public GuiPrescription getNewPrescriptionByPatient(GuiPatient guiPatient) {
		GuiPrescription result = new GuiPrescription();
		result.setPatient(guiPatient);
		result.setTerm(1);
		result.setTermString(CommonUtil.getTermStringByTerm(1));
		Calendar cal = Calendar.getInstance();
		result.setDate(cal.getTime());
		return result;
	}
	
	@Transactional
	public GuiPrescription getNewPrescriptionByRootPrescriptionId(long rootPrescriptionId) {
		GuiPrescription result = new GuiPrescription();
		Prescription oRootPrescription = prescriptionAccessor.getPrescriptionById(rootPrescriptionId);
		if (oRootPrescription != null) {
			Prescription rootPrescription = null;
			if (oRootPrescription.getRootPrescription() != null) {
				rootPrescription = oRootPrescription.getRootPrescription();
			} else {
				rootPrescription = oRootPrescription;
			}
			result.setRootPrescription(ConvertUtil.getGuiPrescriptionByPrescription(rootPrescription));
			
			List<Prescription> prevPrescriptionList = prescriptionAccessor.getPrescriptionsByRootPrescriptionId(rootPrescription.getPrescriptionId());
			prevPrescriptionList.add(rootPrescription);
			
			int prevCount = prevPrescriptionList.size();
			result.setTerm(prevCount + 1);
			result.setTermString(CommonUtil.getTermStringByTerm(prevCount + 1));
			
			Patient patient = patientAccessor.getPatientById(oRootPrescription.getPatient().getUserId());
			result.setPatient(ConvertUtil.getGuiPatientByPatient(patient));
			
			Prescription prevPrescription = prevPrescriptionList.get(0);
			result.setPrevPrescription(ConvertUtil.getGuiPrescriptionByPrescription(prevPrescription));
			
			Calendar cal = Calendar.getInstance();
			result.setDate(cal.getTime());
		}
		return result;
	}
	
	@Transactional
	public GuiPrescription insertPrescription(GuiPrescription guiPrescription) {
		Prescription prescription = new Prescription();
		// set prescription's patient
		Patient patient = patientAccessor.getPatientById(guiPrescription.getPatient().getUserId());
		prescription.setPatient(patient);
		// set root prescription
		if(guiPrescription.getRootPrescription() != null) {
			Prescription rootPrescription = prescriptionAccessor.getPrescriptionById(guiPrescription.getRootPrescription().getPrescriptionId());
			prescription.setRootPrescription(rootPrescription);
		}
		
		// set prescription's symptoms
		prescription.setSyptoms(getSyptomSetByGuiSyptoms(guiPrescription.getSyptomList()));
		
		// set prescription's drug issues
		prescription.setIssues(getDrugIssuesByGuiDrugIssues(guiPrescription.getDrugIssueList(), prescription));
		
		prescription.setVisitIndex(guiPrescription.getTerm());
		prescription.setDiagnosticDescription(guiPrescription.getSymptomDuration() + "|" + guiPrescription.getDiagnosticDescription());
		prescription.setComment(CommonUtil.trim(guiPrescription.getComment()));
		prescription.setDate(guiPrescription.getDate());
		Prescription mPrescription = prescriptionAccessor.insertOrUpdate(prescription);
		
		return ConvertUtil.getGuiPrescriptionByPrescription(mPrescription);
	}
	
	@Transactional
	public GuiPrescription updatePrescription(GuiPrescription guiPrescription) {
		Prescription prescription = prescriptionAccessor.getPrescriptionById(guiPrescription.getPrescriptionId());
		// set symptom information
		prescription.setSyptoms(getSyptomSetByGuiSyptoms(guiPrescription.getSyptomList()));
		// set drug issue information
		prescription.setIssues(getDrugIssuesByGuiDrugIssues(guiPrescription.getDrugIssueList(), prescription));
		
		prescription.setVisitIndex(guiPrescription.getTerm());
		prescription.setDiagnosticDescription(guiPrescription.getSymptomDuration() + "|" + guiPrescription.getDiagnosticDescription());
		prescription.setComment(CommonUtil.trim(guiPrescription.getComment()));
		prescription.setDate(guiPrescription.getDate());
		Prescription mPrescription = prescriptionAccessor.insertOrUpdate(prescription);
		
		return ConvertUtil.getGuiPrescriptionByPrescription(mPrescription);
	}
	
	public GuiPagination getPaginationOfPrescriptions(int page) {
		int total = prescriptionAccessor.countPrescriptions();
		return CommonUtil.getPaginationInfo(page, total);
	}
	
	private Set<Syptom> getSyptomSetByGuiSyptoms(List<GuiSyptom> guiSyptoms) {
		Set<Syptom> syptoms = new HashSet<>();
		if (guiSyptoms != null) {
			for (GuiSyptom guiSyptom : guiSyptoms) {
				if(guiSyptom != null && StringUtils.isNotBlank(guiSyptom.getName())) {
					// check symptom by name already exist or not
					Syptom oSyptom = syptomAccessor.getSyptomByName(guiSyptom.getName());
					if (oSyptom == null) {
						long id = guiSyptom.getSyptomId();
						
						if(id == 0){
							Syptom syptom = ConvertUtil.getSyptomByGuiSyptom(guiSyptom);			
							oSyptom = syptomAccessor.insertOrUpdate(syptom);
						} else {
							oSyptom = syptomAccessor.getSyptomById(id);				
						}
					}
					if (oSyptom != null) {
						syptoms.add(oSyptom);
					}
				}
			}
		}
		return syptoms;
	}
	
	private Set<DrugIssue> getDrugIssuesByGuiDrugIssues(List<GuiDrugIssue> guiDrugIssues, Prescription prescription) {
		Set<DrugIssue> drugIssues = null;
		if (guiDrugIssues != null) {
			drugIssues = new HashSet<>();
			for (GuiDrugIssue guiDrugIssue : guiDrugIssues) {
				if (guiDrugIssue != null && guiDrugIssue.isAvailable()) {
					long drugIssueId = guiDrugIssue.getDrugIssueId();
					DrugIssue drugIssue = null;
					if (drugIssueId == 0) {
						drugIssue = ConvertUtil.getDrugIssueByGuiDrugIssue(guiDrugIssue);
					} else {
						DrugIssue oDrugIssue = drugIssueAccessor.getDrugIssueById(drugIssueId);
						drugIssue = ConvertUtil.getDrugIssueByGuiDrugIssue(guiDrugIssue, oDrugIssue);
					}
					
					if (drugIssue.isIssue()) {
						Drug drug = drugAccessor.getDrugById(guiDrugIssue.getDrug().getDrugId());
						drugIssue.setDrug(drug);
						int recommandedDrugsAmount = drugIssue.getNoOfDays() * drugIssue.getTermsPerDay();
						int waitingDrugsAmount = recommandedDrugsAmount; // drugs to be issue from stocks
						List<DrugStock> drugStockList = drugStockAccessor.getAvailableDrugStocksByDrugId(drug.getDrugId(), new Index());
						for (DrugStock drugStock : drugStockList) {
							int availableDrugsAmount = drugStock.getStockAmount();
							if (availableDrugsAmount >= waitingDrugsAmount) {
								drugStock.setStockAmount(availableDrugsAmount - recommandedDrugsAmount);
								waitingDrugsAmount = 0;
							} else if (availableDrugsAmount < recommandedDrugsAmount && availableDrugsAmount > 0) {
								waitingDrugsAmount = waitingDrugsAmount - availableDrugsAmount;
								drugStock.setStockAmount(0);
							}
							if (waitingDrugsAmount == 0) {
								break;
							}
						}
						drugIssue.setDrugStocks(new HashSet<>(drugStockList));
					}
					
					drugIssue.setPrescription(prescription);
					drugIssues.add(drugIssue);
				}
			}
		}
		return drugIssues;
	}

}
